package emergence.game.hud;

import emergence.entities.Mob;
import emergence.entities.Player;
import emergence.game.Game;
import emergence.game.combat.ability.Ability;
import emergence.game.gfx.Screen.ScreenSelectFilter;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JPanel;

public class Hotbar extends JPanel {

    private static final long serialVersionUID = 1L;
    
    private static Game game;

    private JPanel statusPanel;
    private JPanel actionPanel;
    private JPanel commonActionPanel;
    private JPanel quickPanel;
    private JPanel wheelPanel;

    private JPanel moveButtonWrapper;
    private JPanel attackButtonWrapper;

    private JButton moveButton;
    private JButton attackButton;
    private AttackButtonListener atkListener = new AttackButtonListener();
    private MoveButtonListener movListener = new MoveButtonListener();

    private AbilityButton[][] quickButtons = new AbilityButton[3][10];
    private JPanel[][] quickWrappers = new JPanel[3][10];

    private JButton[] wheelButtons = new JButton[4];
    private JPanel[] wheelWrappers = new JPanel[4];
    
    private ResourceBar healthBar;
    private ResourceBar manaBar;
    private ResourceBar staminaBar;
    private ResourceBar aetherBar;

    public Hotbar(Game game) {
        
        this.game = game;

        actionPanel = new JPanel();
        
        quickPanel = new JPanel(new GridLayout(3, 10));
        for (int i = 0; i < quickButtons.length; i++) {
            for (int j = 0; j < quickButtons[0].length; j++) {
                quickButtons[i][j] = new AbilityButton(((i * 10) + (j + 1)) + "");
                quickWrappers[i][j] = new JPanel();
                quickWrappers[i][j].setLayout(new BorderLayout());
                quickWrappers[i][j].add(quickButtons[i][j], BorderLayout.CENTER);
                quickWrappers[i][j].setBorder(BorderFactory.createEmptyBorder(3, 5, 2, 0));
                quickPanel.add(quickWrappers[i][j]);
            }
        }
        quickPanel.setBorder(BorderFactory.createEmptyBorder(2, 0, 3, 5));

        wheelPanel = new JPanel(new GridLayout(3, 3));
        for (int i = 0; i < 4; i++) {
            wheelButtons[i] = new JButton("P " + (i + 1));
            wheelWrappers[i] = new JPanel();
            wheelWrappers[i].setLayout(new BorderLayout());
            wheelWrappers[i].add(wheelButtons[i], BorderLayout.CENTER);
            wheelWrappers[i].setBorder(BorderFactory.createEmptyBorder(3, 5, 2, 0));
        }
        wheelPanel.add(Box.createRigidArea(new Dimension(1, 1)));
        wheelPanel.add(wheelWrappers[0]);
        wheelPanel.add(Box.createRigidArea(new Dimension(1, 1)));
        wheelPanel.add(wheelWrappers[1]);
        wheelPanel.add(Box.createRigidArea(new Dimension(1, 1)));
        wheelPanel.add(wheelWrappers[2]);
        wheelPanel.add(Box.createRigidArea(new Dimension(1, 1)));
        wheelPanel.add(wheelWrappers[3]);
        wheelPanel.add(Box.createRigidArea(new Dimension(1, 1)));
        wheelPanel.setBorder(BorderFactory.createEmptyBorder(2, 0, 3, 5));

        actionPanel.setLayout(new GridBagLayout());

        commonActionPanel = new JPanel();
        commonActionPanel.setLayout(new GridLayout(2, 1));

        moveButton = new JButton("Move");
        moveButton.addActionListener(movListener);
        moveButtonWrapper = new JPanel();
        moveButtonWrapper.setLayout(new BorderLayout());
        moveButtonWrapper.add(moveButton, BorderLayout.CENTER);
        moveButtonWrapper.setBorder(BorderFactory.createEmptyBorder(10, 20, 10, 20));

        attackButton = new JButton("Attack");
        attackButton.addActionListener(atkListener);
        attackButtonWrapper = new JPanel();
        attackButtonWrapper.setLayout(new BorderLayout());
        attackButtonWrapper.add(attackButton, BorderLayout.CENTER);
        attackButtonWrapper.setBorder(BorderFactory.createEmptyBorder(10, 20, 10, 20));

        commonActionPanel.add(moveButtonWrapper);
        commonActionPanel.add(attackButtonWrapper);

        GridBagConstraints c = new GridBagConstraints();
        c.gridx = 0;
        c.gridy = 0;
        c.fill = GridBagConstraints.BOTH;
        c.weightx = 0.3;
        c.weighty = 0.3;
        c.anchor = GridBagConstraints.LINE_START;
        actionPanel.add(commonActionPanel, c);

        c = new GridBagConstraints();
        c.gridx = 1;
        c.gridy = 0;
        c.fill = GridBagConstraints.BOTH;
        c.weightx = 1.0;
        c.weighty = 1.0;
        c.anchor = GridBagConstraints.LINE_START;
        actionPanel.add(quickPanel, c);

        c = new GridBagConstraints();
        c.gridx = 2;
        c.gridy = 0;
        c.fill = GridBagConstraints.BOTH;
        c.weightx = 0.2;
        c.weighty = 0.2;
        c.anchor = GridBagConstraints.LINE_START;
        actionPanel.add(wheelPanel, c);

        healthBar = new ResourceBar(100, Color.RED);
        healthBar.setTextColor(Color.BLACK);
        staminaBar = new ResourceBar(100, Color.GREEN);
        staminaBar.setTextColor(Color.BLACK);
        manaBar = new ResourceBar(100, Color.BLUE);
        manaBar.setTextColor(Color.WHITE);
        aetherBar = new ResourceBar(100, Color.DARK_GRAY);
        aetherBar.setTextColor(Color.WHITE);
        
        statusPanel = new JPanel();
        statusPanel.setLayout(new GridLayout(1, 4));
        statusPanel.add(healthBar);
        statusPanel.add(staminaBar);
        statusPanel.add(manaBar);
        statusPanel.add(aetherBar);
        
        this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
        this.add(statusPanel);
        this.add(actionPanel);
        
        updatePlayerResources();
    }
    
    private void updatePlayerResources() {
        Player player;
        if ((player = game.getActivePlayer()) != null) {
            healthBar.setValue(player.getHealth().getValue());
            healthBar.setMaxValue(player.getHealth().getMaxValue());
            staminaBar.setValue(player.getStamina().getValue());
            staminaBar.setMaxValue(player.getStamina().getMaxValue());
            manaBar.setValue(player.getMana().getValue());
            manaBar.setMaxValue(player.getMana().getMaxValue());
            aetherBar.setValue(player.getAether().getValue());
            aetherBar.setMaxValue(player.getAether().getMaxValue());
        }
    }
    
    public void render() {
        updatePlayerResources();
        healthBar.repaint();
        manaBar.repaint();
        staminaBar.repaint();
        aetherBar.repaint();
    }
    
    public static class ResourceBar extends JPanel {
        
        private final int EXTERNAL_BORDER_WIDTH = 3;
        private final int BORDER_WIDTH = 3;
        private final Color BORDER_COLOR = Color.BLACK;
        private final Color BACK_COLOR = Color.GRAY;
        
        private final Font labelFont = new Font("Arial", Font.PLAIN, 10);
        
        private int maxValue;
        private int value;
        
        private Color color;
        private Color textColor;
        
        public ResourceBar(int maxValue, Color color) {
            this.maxValue = maxValue;
            this.color = color;
            
            this.textColor = Color.BLACK;
            this.value = maxValue;
            this.setBorder(BorderFactory.createEmptyBorder(EXTERNAL_BORDER_WIDTH, EXTERNAL_BORDER_WIDTH, EXTERNAL_BORDER_WIDTH, EXTERNAL_BORDER_WIDTH));
        }
        
        public void setValue(int value) {
            this.value = value;
        }
        
        public int getValue() {
            return value;
        }
        
        public void setMaxValue(int maxValue) {
            this.maxValue = maxValue;
        }
        
        public int maxValue() {
            return maxValue;
        }
        
        public void setTextColor(Color color) {
            this.textColor = color;
        }
        
        @Override
        public void paintComponent(Graphics g) {
            Graphics2D g2D = (Graphics2D)g.create();
            g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            
            double percent = ((double)value) / ((double)maxValue);
            int width = getWidth() - getInsets().left - getInsets().right;
            int height = getHeight() - getInsets().top - getInsets().bottom;
            int barWidth = (int)Math.round((width - (BORDER_WIDTH * 2)) * percent);
            int barHeight = height - (BORDER_WIDTH * 2);
            int outerCurveRadius = height / 2;
            int innerCurveRadius = barHeight / 2;
            
            g2D.setColor(getBackground());
            g2D.fillRect(0, 0, getWidth(), getHeight());
            
            g2D.setColor(BORDER_COLOR);
            g2D.fillRoundRect(getInsets().left, getInsets().top, width, height, outerCurveRadius, outerCurveRadius);
            g2D.setColor(BACK_COLOR);
            g2D.fillRoundRect(getInsets().left + BORDER_WIDTH, getInsets().top + BORDER_WIDTH, width - (BORDER_WIDTH * 2), height - (BORDER_WIDTH * 2), innerCurveRadius, innerCurveRadius);
            g2D.setColor(color);
            g2D.fillRoundRect(getInsets().left + BORDER_WIDTH, getInsets().top + BORDER_WIDTH, barWidth, barHeight, innerCurveRadius, innerCurveRadius);
            
            g2D.setColor(textColor);
            g2D.setFont(labelFont);
            FontMetrics metrics = g2D.getFontMetrics();
            String centerText = value + "/" + maxValue;
            int centerX = getWidth() / 2;
            int centerY = getHeight() / 2;
            int stringStartX = centerX - (metrics.stringWidth(centerText) / 2);
            int stringStartY = centerY + (metrics.getHeight() / 4);
            g2D.drawString(centerText, stringStartX, stringStartY);
            
            g2D.dispose();
        }
        
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(100, 24);
        }
        
        @Override
        public Dimension getMinimumSize() {
            return new Dimension (1, 20);
        }
        
    }

    public static class AbilityButton extends JButton {
        
        private Ability ability;
        
        public AbilityButton(String s) {
            super(s);
            this.ability = null;
        }
        
        public AbilityButton(Ability ability) {
            super(ability.getName());
            this.ability = ability;
        }
    }
    
    private class AttackButtonListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            game.startSelection(new AttackFilter());
            game.setLastSelectionType(Game.SELECTION_TYPE.ATTACK);
        }
        
    }
    
    private class MoveButtonListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        }
        
    }
    
    public static class AttackFilter implements ScreenSelectFilter {

        @Override
        public boolean acceptEntity(Mob mob) {
            if (mob == null) {
                return false;
            }
            else if (mob.isFriendsWith(game.getActivePlayer())) {
                return false;
            }
            Point other = mob.getCoords();
            Point player = game.getActivePlayer().getCoords();
            if (other.x == player.x) {
                return Math.abs(other.y - player.y) == 1;
            }
            else if (other.y == player.y) {
                return Math.abs(other.x - player.x) == 1;
            }
            return false;
        }
        
    }
    
}
